﻿using System.Reflection;

namespace zijian666.Core;

/// <summary>
/// 程序集解析器
/// </summary>
public partial class AssemblyResolver : AssemblyCollection
{
    /// <summary>
    /// 构造函数
    /// </summary>
    public AssemblyResolver(AppDomain? domain)
        : this(null, domain)
    {

    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public AssemblyResolver(IEnumerable<Assembly>? assemblies)
        : this(assemblies, AppDomain.CurrentDomain)
    {

    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public AssemblyResolver(IEnumerable<Assembly>? assemblies, AppDomain? domain)
    {
        if (domain is not null)
        {
            _ = AddRange(domain.GetAssemblies());
            domain.AssemblyLoad += (_, args) => Add(args.LoadedAssembly);
        }
        if (assemblies is not null)
        {
            _ = AddRange(assemblies);
        }
    }

    /// <summary>
    /// 获取符合指定条件的类型
    /// </summary>
    /// <param name="predicate">筛选条件</param>
    /// <returns></returns>
    public IEnumerable<Type> GetTypes(Func<Type, bool>? predicate = null)
    {
        foreach (var (_, types) in this)
        {
            foreach (var type in types)
            {
                if (predicate is null || predicate(type))
                {
                    yield return type;
                }
            }
        }
    }

    /// <summary>
    /// 获取指定命名空间下的所有类型
    /// </summary>
    /// <param name="namespace">命名空间</param>
    /// <param name="ignoreCase">是否忽略大小写</param>
    /// <returns></returns>
    public IEnumerable<Type> GetTypesWithNamespace(string @namespace, bool ignoreCase = false)
    {
        if (string.IsNullOrWhiteSpace(@namespace))
        {
            throw new ArgumentException($"“{nameof(@namespace)}”不能为 null 或空白。", nameof(@namespace));
        }

        var sc = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
        return @namespace is null ? Type.EmptyTypes : GetTypes(x => x.Namespace?.Equals(@namespace, sc) ?? false);
    }

    /// <summary>
    /// 获取拥有指定特性的类型
    /// </summary>
    /// <typeparam name="T">特性类型</typeparam>
    /// <param name="inherit">是否包含继承的特性</param>
    /// <returns></returns>
    public IEnumerable<(Type, T)> GetTypesWithAttribute<T>(bool inherit = false)
        where T : Attribute
    {
        foreach (var (_, types) in this)
        {
            foreach (var type in types)
            {
                var attrs = type.GetCustomAttributes<T>(inherit);
                if (attrs is not null)
                {
                    foreach (var attr in attrs)
                    {
                        yield return (type, attr);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 获取指定类型的子类或实现类
    /// </summary>
    public IEnumerable<Type> GetTypesWithAssignableFrom(Type baseType)
        => baseType is null ? Type.EmptyTypes : GetTypes(baseType.IsAssignableFrom);
}
